#ifndef MESSAGE_H
#define MESSAGE_H

#include "MessageDefs.h"
#include <string>
#include <vector>

typedef unsigned char byte;


class Buffer;
class Block;

class Message  
{
public:
	static Message* LoadMessage(const Block& B);
	static bool UsingRealTime;
	virtual ~Message();

	virtual void WriteTo(Buffer& B) = 0;
	virtual byte GetMsgId() {return MSG_BAD;};
	virtual Message* Clone() const = 0;

	virtual void RenumberEntity(int OldId, int NewId) {};
	virtual void ShiftEntity(int Id, int Offset[3]) {};
	virtual void MergeInto(Block& pOther,int ClientNumber) {};
	virtual bool IsUpdateFor(int EntityId) {return false;};
	virtual bool IsClientData() {return false;};
protected:
	Message(const Buffer& B) {};
	Message() {};
};

#define SPECIFIC_MESSAGE(Specific,Parent,MSG_ID) \
class Specific : public Parent \
{\
private:\
	Specific(const Buffer& B) : Parent(B) {};\
	virtual byte GetMsgId() {return MSG_ID;};\
	friend class Message;\
	virtual Message* Clone() const {return new Specific(*this);};\
	Specific(const Specific& Other) :Parent(Other) {};\
};

#define IMPL_CLONE(name)\
	virtual Message* Clone() const {return new name(*this);};


////////////////////// Generic messages

class MessageVoid : public Message
{
protected:
	MessageVoid(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	IMPL_CLONE(MessageVoid);
	friend class Message;
};

class MessageByte : public Message
{
protected:
	MessageByte(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	IMPL_CLONE(MessageByte);
	friend class Message;
protected:
	char	m_Value;
};


class MessageShort : public Message
{
protected:
	MessageShort(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageShort);
protected:
	short		m_Value;
};

class MessageLong : public Message
{
protected:
	MessageLong(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageLong);
protected:
	long		m_Value;
};

class MessageByteByte : public Message
{
protected:
	MessageByteByte(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageByteByte);

	char		m_First;
	char		m_Second;
};

class MessageByteShort : public Message
{
protected:
	MessageByteShort(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageByteShort);

	char		m_First;
	short		m_Second;
};

class MessageText : public Message
{
protected:
	MessageText(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageText);

	std::string	m_Data;
};


class MessageByteString : public Message
{
protected:
	MessageByteString(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageByteString);
	
	char		m_Id;
	std::string m_Text;
};


template <int Size>
class MessageRawData : public Message
{
protected:
	MessageRawData(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageRawData);
	
	char		m_Data[Size];
};


/////////////////// Specific messages

SPECIFIC_MESSAGE(MessageBad,			MessageVoid,MSG_BAD);
SPECIFIC_MESSAGE(MessageNOP,			MessageVoid,MSG_NOP);
SPECIFIC_MESSAGE(MessageSpawnbinary,	MessageVoid,MSG_SPAWNBINARY);
SPECIFIC_MESSAGE(MessageDisconnect,		MessageVoid,MSG_DISCONNECT);
SPECIFIC_MESSAGE(MessageSellscreen,		MessageVoid,MSG_SELLSCREEN);
SPECIFIC_MESSAGE(MessageKilledmonster,	MessageVoid,MSG_KILLEDMONSTER);
SPECIFIC_MESSAGE(MessageFoundSecret,	MessageVoid,MSG_FOUNDSECRET);

SPECIFIC_MESSAGE(MessageSetpause,		MessageByte,MSG_SETPAUSE);

SPECIFIC_MESSAGE(MessageStopsound,		MessageShort,MSG_STOPSOUND);

SPECIFIC_MESSAGE(MessageVersion,		MessageLong,MSG_VERSION);

SPECIFIC_MESSAGE(MessagePrint,			MessageText,MSG_PRINT);
SPECIFIC_MESSAGE(MessageStufftext,		MessageText,MSG_STUFFTEXT);

SPECIFIC_MESSAGE(MessageCDtrack,		MessageByteByte,MSG_CDTRACK);
SPECIFIC_MESSAGE(MessageUpdateColor,	MessageByteByte,MSG_UPDATECOLOR);

SPECIFIC_MESSAGE(MessageUpdatefrags,	MessageByteShort,MSG_UPDATEFRAGS);

SPECIFIC_MESSAGE(MessageLightstyle,		MessageByteString,MSG_LIGHTSTYLE);
SPECIFIC_MESSAGE(MessageUpdatename,		MessageByteString,MSG_UPDATENAME);

SPECIFIC_MESSAGE(MessageDamage,			MessageRawData<8>,MSG_DAMAGE);
SPECIFIC_MESSAGE(MessageSpawnstatSound,	MessageRawData<9>,MSG_SPAWNSTATICSOUND);
SPECIFIC_MESSAGE(MessageParticle,		MessageRawData<11>,MSG_PARTICLE);
SPECIFIC_MESSAGE(MessageSpawnstatic,	MessageRawData<13>,MSG_SPAWNSTATIC);
//SPECIFIC_MESSAGE(MessageSpawnBaseLine,	MessageRawData<15>,MSG_SPAWNBASELINE);

// really special messages

class MessageUpdatestat : public Message
{
protected:
	MessageUpdatestat(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageUpdatestat);

	char		m_Index;
	long		m_Value;
};

class MessageSound : public Message
{
protected:
	MessageSound(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageSound);
private:
	byte m_Mask;
	byte m_Vol;
	byte m_Att;
	byte m_Data[9];
};

class MessageTime : public Message
{
protected:
	MessageTime(const Block& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageTime);

	float m_Time;
};

class MessageSetangles : public Message
{
public:
	MessageSetangles() {};
	void SetAng(int Index, float Value)
	{
		m_Angles[Index] = (byte)(Value / 360.0 * 255);
	}
	virtual void WriteTo(Buffer& B);
protected:
	MessageSetangles(const Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageSetangles);

	byte m_Angles[3];
};


class MessageServerinfo : public Message
{
protected:
	MessageServerinfo(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageServerinfo);

	long		m_Serverversion;
	byte		m_MaxClients;
	byte		m_Multi;
	std::string m_MapName;

//	std::vector<std::string> m_Models;
	std::vector<std::string> m_Sounds;
	
};


class MessageClientdata : public Message
{
public:
	virtual void MergeInto(Block& pOther,int ClientNumber);
protected:
	MessageClientdata(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageClientdata);
	virtual bool IsClientData() {return true;};

private:
	unsigned short	m_Mask;
	byte m_PunchangleX;
	byte m_ViewOffsZ;	
	byte m_Angs[3];
	byte m_Vel[3];
	unsigned long m_Items;
	byte m_WeaponFrame;
	byte m_ArmorValue;
	byte m_WeaponModel;
	unsigned short m_Health;
	byte m_Ammo;
	byte m_Ammos[4];
	byte m_Weapon;
};



class MessageTempEntity : public Message
{
protected:
	MessageTempEntity(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageTempEntity);

	byte m_Type;
	short m_EntityId;
	short m_Coords[3];
	short m_EndCoords[3];
};


class MessageUpdateEntity : public Message
{
public:
	MessageUpdateEntity(int EntityId,float Origin[3],float Angles[3]);
	virtual void WriteTo(Buffer& B);
	virtual void ShiftEntity(int Id, int Offset[3]);
	virtual void MergeInto(Block& pOther,int ClientNumber);
	virtual bool IsUpdateFor(int EntityId);

	virtual void RenumberEntity(int OldId, int NewId);

protected:
	MessageUpdateEntity(const Buffer& B,byte Id);
	friend class Message;
	IMPL_CLONE(MessageUpdateEntity);

	short m_Mask;

	short m_EntityId;

	int m_Modelindex;
	byte m_Frame;
	byte m_Colormap;
	byte m_Skin;
	byte m_AttackState;
	
	short m_Origin[3];
	byte m_Angles[3];
};

class MessageSetView : public Message
{
protected:
	MessageSetView(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageSetView);
protected:
	short		m_EntityId;
};

class MessageSignonUp : public Message
{
protected:
	MessageSignonUp(const Buffer& B);
	virtual void WriteTo(Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageSignonUp);
protected:
	byte		m_Signon;
};

class MessageCenterprint : public Message
{
public:
	MessageCenterprint(std::string Text) {m_Data = Text;};
	virtual void WriteTo(Buffer& B);
	IMPL_CLONE(MessageCenterprint);
protected:
	MessageCenterprint(const Buffer& B);
	friend class Message;

	std::string	m_Data;
};

class MessageIntermission : public Message
{
protected:
	virtual void WriteTo(Buffer& B);
	MessageIntermission(const Block& B);
	friend class Message;
	IMPL_CLONE(MessageIntermission);
};

class MessageFinale : public Message
{
protected:
	virtual void WriteTo(Buffer& B);
	MessageFinale(const Block& B);
	friend class Message;
	IMPL_CLONE(MessageFinale);

	std::string	m_Data;
};




class MessageSpawnBaseLine : public Message
{
public:
	virtual void WriteTo(Buffer& B);
	virtual void MergeInto(Block& pOther,int ClientNumber);
	virtual bool IsUpdateFor(int EntityId);
	virtual void RenumberEntity(int OldId, int NewId);
	virtual void ShiftEntity(int Id, int Offset[3]);
protected:
	MessageSpawnBaseLine(const Buffer& B);
	friend class Message;
	IMPL_CLONE(MessageSpawnBaseLine);

	short m_EntityId;

	byte m_Modelindex;
	byte m_Frame;
	byte m_Colormap;
	byte m_Skin;
	
	short m_Origin[3];
	byte m_Angles[3];
};

#endif 

